#ifndef AGT_VEC3_H
#define AGT_VEC3_H

namespace agtk {

/** 3D Vector Class (generic type)
	@author Tom Savage
**/
template <class type> class Vec3 {
private:
	// Store x, y and z components in array.
	type v[3];
public:
	Vec3(void) {
		// Set default values to 0 as we have no other data.
		v[0] = 0;
		v[1] = 0;
		v[2] = 0;
	}

	Vec3(type valueX, type valueY, type valueZ) {
		// Set default values to the ones given.
		v[0] = valueX;
		v[1] = valueY;
		v[2] = valueZ;
	}

	~Vec3(void) {
		// Empty destructor.
	}

	type Get(unsigned int index) {
		// Return the requested component.
		return v[index];
	}
	
	std::string GetStringFormat(void) {
		// Create a string stream for formatted output of the data.
		std::ostringstream oss (std::ostringstream::out);
		// Put data into string stream like you would with cout of other similar functions.
		oss << "V3("<<v[0] << "," << v[1] << "," << v[2]<<")";
		// Return a string version of the string stream.
		return oss.str();
	}

	void Set(unsigned int index, type value) {
		// Set the given component to the new value.
		v[index]=value;
	}

	void Set(type valueX, type valueY, type valueZ) {
		// Set each component to it's new value.
		v[0] = valueX;
		v[1] = valueY;
		v[2] = valueZ;
	}

	type Magnitude(void) const {
		// Basically pythag in 3D.
		return sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
	}

	type MagnitudeSquared(void) const {
		// No need to square root :D
		return v[0] * v[0] + v[1] * v[1] + v[2] * v[2];
	}

	Vec3<type> Normalize(void) const {
		// Divide each component by the magnitude.
		type m = sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
		return Vec3(v[0] / m, v[1] / m, v[2] / m);
	}
	
	Vec3<type> operator*(float scale) const {
		// Multiply each component by the scale value.
		return Vec3(v[0] * scale, v[1] * scale, v[2] * scale);
	}
	
	Vec3<type> operator/(float scale) const {
		// Divide each component by the scale value.
		return Vec3(v[0] / scale, v[1] / scale, v[2] / scale);
	}
	
	Vec3<type> operator+(const Vec3 &other) const {
		// Add vectors together. Gives you a new vector. Shortest path from start of A to end of B.
		return Vec3(v[0] + other.v[0], v[1] + other.v[1], v[2] + other.v[2]);
	}
	
	Vec3<type> operator-(const Vec3 &other) const {
		return Vec3(v[0] - other.v[0], v[1] - other.v[1], v[2] - other.v[2]);
	}
	
	Vec3<type> operator-() const {
		// Invert each component.
		return Vec3(-v[0], -v[1], -v[2]);
	}
	
	const Vec3<type> &operator*=(float scale) {
		v[0] *= scale;
		v[1] *= scale;
		v[2] *= scale;
		return *this;
	}
	
	const Vec3<type> &operator/=(float scale) {
		v[0] /= scale;
		v[1] /= scale;
		v[2] /= scale;
		return *this;
	}
	
	const Vec3<type> &operator+=(const Vec3 &other) {
		v[0] += other.v[0];
		v[1] += other.v[1];
		v[2] += other.v[2];
		return *this;
	}
	const Vec3<type> &operator-=(const Vec3 &other) {
		v[0] -= other.v[0];
		v[1] -= other.v[1];
		v[2] -= other.v[2];
		return *this;
	}
};

}
#endif